﻿using System;
using System.ComponentModel;
using System.Diagnostics;
using System.Drawing;

using System.Windows.Forms;
using RayDen.Library.Core;
using RayDen.Library.Core.Primitives;
using RayDen.SceneLab.Controllers.FormControllers;

namespace RayDen.SceneLab.UI
{
    public partial class ProceduralTextureEditorForm : Form
    {
        protected ProceduralTextureEditorController Controller;

        public ToolStripProgressBar Progress
        {
            get { return this.toolStripProgressBar1; }
        }

        public PictureBox Canvas
        {
            get { return this.ctlCanvas; }
        }

        public RichTextBox TxtExpression
        {
            get { return txtExpression; }
        }

        public ProceduralTextureEditorForm()
        {
            InitializeComponent();
        }
        protected override void OnLoad(EventArgs e)
        {
            base.OnLoad(e);
            Controller = new ProceduralTextureEditorController(this);
            this.lblCommands.Text = ProceduralTextureEditorController.ParamsLegend;
            this.lstAtlas.DataSource = this.Controller.Names;
        }

        private void openToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (dlgOpenImage.ShowDialog() == DialogResult.OK)
            {
                this.Controller.OpenFile(dlgOpenImage.FileName);
                this.groupBox1.Text = this.Controller.ImageName;
                this.ctlCanvas.Image = new Bitmap(this.Controller.Image);
                //this.ctlCanvas.Refresh();
            }
        }

        protected override void WndProc(ref Message m)
        {
            base.WndProc(ref m);
            if (this.IsDisposed)
                return;
            if (m.HWnd != this.Handle)
            {
                return;
            }
            switch (m.Msg)
            {
                case 0x020E: //Win32Messages.WM_MOUSEHWHEEL:
                    FireMouseHWheel(m.WParam, m.LParam);
                    m.Result = (IntPtr)1;
                    break;
                default:
                    break;
            }
        }

        private void FireMouseHWheel(IntPtr intPtr1, IntPtr intPtr2)
        {
            var w = intPtr1.ToInt32();
            var l = intPtr2.ToInt32();
            MessageBox.Show("WHeel" + w + " : " + l, "Wheel event");
        }

        protected override void OnClosing(CancelEventArgs e)
        {
            this.Controller.Dispose();
            base.OnClosing(e);
        }

        private async void btnEval_Click(object sender, EventArgs e)
        {
            if (Controller.IsEvaluating)
            {
                this.Controller.CancelEvaluation();
                this.btnEval.Text = "Evaluate";
                this.toolStripStatusLabel1.Text = "Evaluation canceled";
                Trace.WriteLine("Evaluating solid texture canceled");
            }
            else
            {
                ColorizeText();


                this.ctlCanvas.Image = Controller.Image;
                var start = DateTime.UtcNow;
                Trace.WriteLine("Evaluating solid texture");
                this.toolStripStatusLabel1.Text = "Start Evaluating Texture";
                this.btnEval.Text = "Cancel evaluation";
                var c = await this.Controller.Eval(this.txtExpression.Text.Trim());
                this.btnEval.Text = "Evaluate";
                this.toolStripStatusLabel1.Text = "Texture evaluated in " + (DateTime.UtcNow - start);
                Trace.WriteLine("Evaluating solid texture ended in " + (DateTime.UtcNow - start));

                this.Controller.RefreshImage();
                this.Controller.CleanImage();
                this.Refresh();
            }
        }



        private void ColorizeText()
        {
            Colorize("$", ">", Color.DodgerBlue);
            //ColorizeWords(Color.Firebrick, "unit");//, "c", "e", "p", "x", "y", "nr", "nz", "nc"
        }

        private void Colorize(string start, string end, Color color)
        {
            var currentIndex = 0;
            int iter = 0;
            while (currentIndex != -1)
            {
                currentIndex = txtExpression.Text.IndexOf(start, currentIndex, StringComparison.InvariantCultureIgnoreCase);
                if (currentIndex == -1)
                {
                    return;
                }
                if (txtExpression.Text.IndexOf('>', currentIndex) == -1)
                    return;
                txtExpression.SelectionStart = currentIndex;
                var font = (Font)txtExpression.SelectionFont.Clone();
                //using 
                var selectionFont = new Font(font.FontFamily, font.Size, FontStyle.Bold | FontStyle.Underline);
                {
                    txtExpression.SelectionFont = selectionFont;
                    txtExpression.SelectionLength =
                        txtExpression.Text.IndexOf(end, currentIndex, StringComparison.InvariantCultureIgnoreCase) -
                        currentIndex + 1;
                    txtExpression.SelectionColor = color;
                }
                txtExpression.Font = font;
                txtExpression.SelectionStart = 0;
                txtExpression.SelectionLength = 0;
                iter++;
                currentIndex++;
                if (iter == 100)
                {
                    break;
                }
            }
        }

        private void ColorizeWords(Color color, params string[] words)
        {
            var currentIndex = 0;
            int iter = 0;
            foreach (var word in words)
            {
                while (currentIndex != -1)
                {
                    currentIndex = txtExpression.Text.IndexOf(word, currentIndex, StringComparison.InvariantCultureIgnoreCase);
                    if (currentIndex == -1)
                    {
                        return;
                    }
                    txtExpression.SelectionStart = currentIndex;
                    txtExpression.SelectionLength = currentIndex + word.Length;
                    txtExpression.SelectionFont = new Font(txtExpression.SelectionFont, FontStyle.Bold);
                    txtExpression.SelectionColor = color;

                    txtExpression.SelectionStart = 0;
                    txtExpression.SelectionLength = 0;
                    iter++;
                    currentIndex++;
                    if (iter == 10)
                    {
                        break;
                    }
                }
            }

        }

        private void ctlCanvas_Paint(object sender, PaintEventArgs e)
        {
            if (this.Controller.Image != null)
            {
                e.Graphics.DrawImage(this.Controller.Image, 0, 0);
            }

        }

        private void ctlBaseColor_Paint(object sender, PaintEventArgs e)
        {
            using (var sb = new SolidBrush(this.Controller.BaseColor.ToColor()))
            {
                e.Graphics.FillRectangle(sb, ctlBaseColor.ClientRectangle);
            }
        }

        private void lnkBaseColor_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
        {
            if (colorDialog1.ShowDialog() == DialogResult.OK)
            {
                this.Controller.BaseColor = RgbSpectrum.Create(colorDialog1.Color);
            }
            this.Refresh();
        }

        private void toolStripStatusLabel2_Paint(object sender, PaintEventArgs e)
        {
            toolStripStatusLabel2.Text = "GS: " + this.Controller.GenerationStatus;
        }

        private void btnRefresh_Click(object sender, EventArgs e)
        {
            this.Controller.RefreshImage();
        }

        private void ProceduralTextureEditorForm_KeyPress(object sender, KeyPressEventArgs e)
        {
            if (e.KeyChar == ((char)27))
            {

            }
        }

        private void ProceduralTextureEditorForm_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.Escape && this.Controller.IsEvaluating)
            {
                this.Controller.CancelEvaluation();
                this.toolStripStatusLabel1.Text = "Evaluating aborted";
            }
        }

        private void lblCommands_Click(object sender, EventArgs e)
        {

        }

        private void ProceduralTextureEditorForm_Load(object sender, EventArgs e)
        {

        }

        private void saveToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (string.IsNullOrWhiteSpace(txtName.Text))
            {
                MessageBox.Show("Name is empty", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return;
            }
            if (string.IsNullOrWhiteSpace(txtExpression.Text))
            {
                MessageBox.Show("Expression is empty", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return;
            }
            this.Controller.SaveTexture(this.txtName.Text, this.txtExpression.Text, this.Controller.BaseColor, this.Controller.BaseImageName);
            this.toolStripStatusLabel1.Text = txtName.Text + " saved to atlas";
            this.lstAtlas.DataSource = this.Controller.Names;
            this.lstAtlas.Refresh();
        }

        private void saveImageToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (dlgSaveImage.ShowDialog() == DialogResult.OK)
            {
                this.Canvas.Image.Save(dlgSaveImage.FileName);
                this.toolStripStatusLabel1.Text = dlgSaveImage.FileName + " Saved";
            }
        }

        private void ctlToolboxTabs_TabIndexChanged(object sender, EventArgs e)
        {
            this.lblCommands.Text = ProceduralTextureEditorController.ParamsLegend;
            this.lstAtlas.DataSource = this.Controller.Names;
        }

        private void txtExpression_TextChanged(object sender, EventArgs e)
        {


        }

        private void btnSaveAtlas_Click(object sender, EventArgs e)
        {
            if (dlgSaveVault.ShowDialog() == DialogResult.OK)
            {
                this.Controller.SaveVault(dlgSaveVault.FileName);
                this.toolStripStatusLabel1.Text = "Texture vault saved : " + dlgSaveVault.FileName;
            }
        }

        private void btnLoadAtlas_Click(object sender, EventArgs e)
        {
            if (dlgOpenVault.ShowDialog() == DialogResult.OK)
            {
                this.Controller.LoadVault(dlgOpenVault.FileName);
                this.lblCommands.Text = ProceduralTextureEditorController.ParamsLegend;
                this.lstAtlas.DataSource = this.Controller.Names;
                this.toolStripStatusLabel1.Text = "Texture vault loaded : " + dlgSaveVault.FileName;
            }
        }

        private void lstAtlas_SelectedIndexChanged(object sender, EventArgs e)
        {
            var selectedTexture = this.Controller.LoadTexture(lstAtlas.SelectedItem.ToString());
            txtExpression.Text = selectedTexture.Expression;
            if (selectedTexture.BaseConstTexture != null)
            {
                this.Controller.BaseColor = (RgbSpectrum) selectedTexture.BaseConstTexture.Color;
                this.ctlBaseColor.Refresh();
            }
            if (selectedTexture.BaseImageTexture != null)
            {
                this.Controller.LoadBaseImage(selectedTexture.BaseImageTexture.FilePath);
                this.ctlBaseImageCanvas.Refresh();
            }
            txtName.Text = selectedTexture.Name;
            this.toolStripStatusLabel1.Text = "Selected texture " + selectedTexture.Name;
            ctlToolboxTabs.SelectTab(0);
        }

        private void btnPutToAtlas_Click(object sender, EventArgs e)
        {
            this.saveToolStripMenuItem_Click(sender, e);
        }

        private void lnkBaseImage_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
        {
            if (dlgOpenImage.ShowDialog() == DialogResult.OK)
            {
                this.Controller.LoadBaseImage(dlgOpenImage.FileName);
                this.ctlBaseImageCanvas.Refresh();
            }
        }

        private void ctlBaseImageCanvas_Paint(object sender, PaintEventArgs e)
        {
            if (this.Controller.BaseBitmap != null)
            {
                e.Graphics.DrawImage(this.Controller.BaseBitmap, 0, 0, ctlBaseImageCanvas.ClientRectangle.Width, ctlBaseImageCanvas.ClientRectangle.Height);
            }
        }

        private void uniformToolStripMenuItem_Click(object sender, EventArgs e)
        {
            this.Controller.SplatProvider(new FastRandom());
        }

        private void haltonToolStripMenuItem_Click(object sender, EventArgs e)
        {
            this.Controller.SplatProvider(new HaltonSequence());
        }

        private void vandercoruptToolStripMenuItem_Click(object sender, EventArgs e)
        {
            this.Controller.SplatProvider(new BaseQMCSequence());
        }

        private void lDToolStripMenuItem_Click(object sender, EventArgs e)
        {
            this.Controller.SplatProvider(new LowDiscrepancySequence());
        }

        private void sobolToolStripMenuItem_Click(object sender, EventArgs e)
        {
            this.Controller.SplatProvider(new JitteredRandom());

        }
    }

}
